﻿namespace MicroCloud.Options
{
    /// <summary>
    /// 系统配置选项创建器
    /// </summary>
    public class MicroCloudOptionsSetup : IConfigureOptions<MicroCloudOptions>
    {
        //字段
        private readonly IConfiguration _configuration;

        #region 构造函数
        /// <summary>
        /// 初始化一个系统配置选项创建器 <see cref="MicroCloudOptionsSetup"/> 的新实例
        /// </summary>
        /// <param name="configuration">系统配置器</param>
        public MicroCloudOptionsSetup(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        #endregion

        #region 方法
        /// <summary>
        /// 配置系统选项配置实例
        /// </summary>
        /// <param name="options">要配置的选项实例</param>
        public void Configure(MicroCloudOptions options)
        {
            if (options == null)
            {
                throw new Exception("配置系统选项配置实例时要配置的选项实例必须实例化");
            }
            options.DbContexts.Clear();
            options.OAuth2.Clear();

            //数据库上下文 DbContexts
            SetDbContextOptions(options);

            IConfigurationSection section;
            //雪花算法配置 Snowflake
            section = _configuration.GetSection("MicroCloud:Snowflake");
            SnowflakeOption snowflake = section.Get<SnowflakeOption>();
            if (snowflake != null)
            {
                snowflake.WorkerId = snowflake.WorkerId <= 0 ? _configuration["MicroCloud:Snowflake:WorkerId"].CastTo<ushort>(0) : snowflake.WorkerId;
                snowflake.StartTimeStampUtc = snowflake.StartTimeStampUtc <= 0 ? _configuration["MicroCloud:Snowflake:StartTimeStampUtc"].CastTo(-1) : snowflake.StartTimeStampUtc;
                options.Snowflake = snowflake;
            }
            //第三方OAuth2登录 OAuth2
            section = _configuration.GetSection("MicroCloud:OAuth2");
            IDictionary<string, OAuth2Option> dict = section.Get<Dictionary<string, OAuth2Option>>();
            if (dict != null)
            {
                foreach (KeyValuePair<string, OAuth2Option> item in dict)
                {
                    options.OAuth2.Add(item.Key, item.Value);
                }
            }
            //Http通信加密选项 HttpEncrypt
            section = _configuration.GetSection("MicroCloud:HttpEncrypt");
            HttpEncryptOption httpEncrypt = section.Get<HttpEncryptOption>();
            if (httpEncrypt != null)
            {
                options.HttpEncrypt = httpEncrypt;
            }
            //电子邮件配置 Email
            section = _configuration.GetSection("MicroCloud:Email");
            EmailOption email = section.Get<EmailOption>();
            if (email != null)
            {
                options.Email = email;
            }
            //JWT身份认证选项 JwtOption
            section = _configuration.GetSection("MicroCloud:Jwt");
            JwtOption jwt = section.Get<JwtOption>();
            if (jwt != null)
            {
                jwt.Secret ??= _configuration["MicroCloud:Jwt:Secret"];
                options.Jwt = jwt;
            }
            //Cookie身份认证选项 CookieOption
            section = _configuration.GetSection("MicroCloud:Cookie");
            CookieOption cookie = section.Get<CookieOption>();
            if (cookie != null)
            {
                options.Cookie = cookie;
            }
            //Cors跨域策略 CorsOption
            section = _configuration.GetSection("MicroCloud:Cors");
            CorsOption cors = section.Get<CorsOption>();
            if (cors != null)
            {
                options.Cors = cors;
            }

            //Mvc选项 MvcOption
            section = _configuration.GetSection("MicroCloud:Mvc");
            MvcOption mvc = section.Get<MvcOption>();
            if (mvc != null)
            {
                mvc.ReferenceLoopHandling = mvc.ReferenceLoopHandling.IsMissing() ? _configuration["MicroCloud:Mvc:ReferenceLoopHandling"] : mvc.ReferenceLoopHandling;
                mvc.ReferenceLoopHandling = mvc.ReferenceLoopHandling.IsMissing() ? "Ignore" : mvc.ReferenceLoopHandling;

                mvc.NullValueHandling = mvc.NullValueHandling.IsMissing() ? _configuration["MicroCloud:Mvc:NullValueHandling"] : mvc.NullValueHandling;
                mvc.NullValueHandling = mvc.NullValueHandling.IsMissing() ? "Include" : mvc.NullValueHandling;

                mvc.DateFormatHandling = mvc.DateFormatHandling.IsMissing() ? _configuration["MicroCloud:Mvc:DateFormatHandling"] : mvc.DateFormatHandling;
                mvc.DateFormatHandling = mvc.DateFormatHandling.IsMissing() ? "Iso" : mvc.DateFormatHandling;

                mvc.DateTimeZoneHandling = mvc.DateTimeZoneHandling.IsMissing() ? _configuration["MicroCloud:Mvc:DateTimeZoneHandling"] : mvc.DateTimeZoneHandling;
                mvc.DateTimeZoneHandling = mvc.DateTimeZoneHandling.IsMissing() ? "Local" : mvc.DateTimeZoneHandling;

                mvc.DateParseHandling = mvc.DateParseHandling.IsMissing() ? _configuration["MicroCloud:Mvc:DateParseHandling"] : mvc.DateParseHandling;
                mvc.DateParseHandling = mvc.DateParseHandling.IsMissing() ? "DateTime" : mvc.DateParseHandling;

                options.Mvc = mvc;
            }

            //SignalR实时通信配置 SignalROption
            section = _configuration.GetSection("MicroCloud:SignalR");
            SignalROption signalR = section.Get<SignalROption>();
            if (signalR != null)
            {
                signalR.ClientTimeoutInterval = signalR.ClientTimeoutInterval <= 0 ? 30 : signalR.ClientTimeoutInterval;

                signalR.HandshakeTimeout = signalR.HandshakeTimeout <= 0 ? 15 : signalR.HandshakeTimeout;

                signalR.KeepAliveInterval = signalR.KeepAliveInterval <= 0 ? 15 : signalR.KeepAliveInterval;

                signalR.MaximumReceiveMessageSize ??= _configuration["MicroCloud:SignalR:MaximumReceiveMessageSize"].CastTo(32);
                signalR.MaximumReceiveMessageSize = signalR.MaximumReceiveMessageSize <= 0 ? 32 : signalR.MaximumReceiveMessageSize;

                signalR.StreamBufferCapacity ??= _configuration["MicroCloud:SignalR:StreamBufferCapacity"].CastTo(10);
                signalR.StreamBufferCapacity = signalR.StreamBufferCapacity <= 0 ? 10 : signalR.StreamBufferCapacity;

                signalR.RoutePattern ??= _configuration["MicroCloud:SignalR:RoutePattern"];
                //if (signalR.RoutePattern.IsMissing())
                //{
                //    throw new MicroCloudException("配置文件中SignalR节点的RoutePattern不能为空");
                //}

                options.SignalR = signalR;
            }

            //缓存选项信息 RedisOption
            section = _configuration.GetSection("MicroCloud:Redis");
            RedisOption redis = section.Get<RedisOption>();
            if (redis != null)
            {
                if (redis.Enabled && redis.Configuration.IsMissing())
                {
                    throw new Exception(I18N.T("配置文件中 Redis 节点的 Configuration 不能为空"));
                }
                options.Redis = redis;
            }

            //Swagger选项 SwaggerOption
            section = _configuration.GetSection("MicroCloud:Swagger");
            SwaggerOption swagger = section.Get<SwaggerOption>();
            if (swagger != null)
            {
                swagger.UI = swagger.UI == null ? "swagger" : swagger.UI.ToLower();
                if (swagger.UI != "swagger" && swagger.UI != "knife4j")
                {
                    swagger.UI = "swagger";
                }
                if (swagger.RoutePrefix.IsNullOrWhiteSpace())
                {
                    swagger.RoutePrefix = "swagger";
                }
                // xml文档 过滤规则
                swagger.XmlPattern ??= "microcloud*.xml";

                // 分组
                swagger.Groups ??= new List<SwaggerGroup>();

                options.Swagger = swagger;
            }

            //设置系统选项配置的单例实例
            Singleton<MicroCloudOptions>.Instance = options;

        }

        /// <summary>
        /// 初始化上下文配置信息，首先以MicroCloud配置节点中的为准，
        /// 不存在MicroCloud节点，才使用ConnectionStrings的数据连接串来构造SqlServer的配置，
        /// 保证同一上下文类型只有一个配置节点
        /// </summary>
        /// <param name="options"></param>
        private void SetDbContextOptions(MicroCloudOptions options)
        {
            // 字符串 Persist Security Info 信息
            //string persistSecurity = "persist security info";
            IConfigurationSection section = _configuration.GetSection("MicroCloud:DbContexts");
            IDictionary<string, DbContextOption> dict = section.Get<Dictionary<string, DbContextOption>>();
            if (dict == null || dict.Count == 0)
            {
                string connectionString = _configuration["ConnectionStrings:DefaultDbContext"];
                if (connectionString == null)
                {
                    return;
                }
                #region "设置连接字符串 Persist Security Info 信息"
                //DbConnectionStringBuilder builder = new() { ConnectionString = connectionString };
                //if (builder.ContainsKey(persistSecurity)) { builder.Remove(persistSecurity); }
                //builder.Add(persistSecurity, true);
                #endregion
                // 增加上下文连接
                DbContextOption dbContextOption = new()
                {
                    DbContextTypeName = "MicroCloud.Auth.DbContext.DefaultDbContext,MicroCloud.Auth.DbContex",
                    //ConnectionString = builder.ConnectionString,
                    ConnectionString = connectionString,
                    DatabaseType = DatabaseType.SqlServer,
                };
                options.DbContexts.Add("DefaultDbContext", dbContextOption);
                return;
            }
            var repeated = dict.Values.GroupBy(m => m.DbContextType).FirstOrDefault(m => m.Count() > 1);
            if (repeated != null)
            {
                throw new Exception(I18N.T("数据上下文配置中存在多个配置节点指向同一个上下文类型：{0}", repeated.First().DbContextTypeName));
            }

            foreach (KeyValuePair<string, DbContextOption> pair in dict)
            {
                #region "设置连接字符串 Persist Security Info 信息"
                // 数据库类型
                //var databaseType = pair.Value.DatabaseType;
                //DbConnectionStringBuilder builder = new() { ConnectionString = pair.Value.ConnectionString };
                //if (databaseType != DatabaseType.Sqlite)
                //{
                //    if (builder.ContainsKey(persistSecurity)) { builder.Remove(persistSecurity); }
                //    builder.Add(persistSecurity, true);
                //}
                //pair.Value.ConnectionString = builder.ConnectionString;
                //foreach (var slaveDatabase in pair.Value.SlaveDatabase.SlaveDatabases)
                //{
                //    DbConnectionStringBuilder slaveDbBuilder = new() { ConnectionString = slaveDatabase.ConnectionString };
                //    if (slaveDbBuilder.ContainsKey(persistSecurity)) { slaveDbBuilder.Remove(persistSecurity); }
                //    slaveDbBuilder.Add(persistSecurity, true);
                //    slaveDatabase.ConnectionString = slaveDbBuilder.ConnectionString;
                //}
                #endregion
                // 增加上下文连接
                options.DbContexts.Add(pair.Key, pair.Value);
            }
        }

        #endregion

    }

}
